package com.nchu.ft.common.util;

import java.util.UUID;

import java.net.*;
import java.security.SecureRandom;
import java.util.concurrent.atomic.AtomicLong;

public class UUIDUtil {

    // UUID版本1的起始时间偏移：1582-10-15 到 1970-01-01 的100纳秒数
    private static final long START_EPOCH = 0x01b21dd213814000L;

    // 上一次的时间戳和时钟序列（14位）
    private static final AtomicLong lastTimestamp = new AtomicLong(0);
    private static final AtomicLong clockSequence = new AtomicLong(new SecureRandom().nextInt(0x3fff));

    // 节点ID（48位），通常为MAC地址，失败则随机生成
    private static final long nodeIdentifier = createNodeIdentifier();

    // 生成节点ID
    private static long createNodeIdentifier() {
        try {
            NetworkInterface network = NetworkInterface.getByInetAddress(InetAddress.getLocalHost());
            byte[] mac = network.getHardwareAddress();
            if (mac != null) {
                long node = 0;
                for (byte b : mac) {
                    node = (node << 8) | (b & 0xFF);
                }
                return node;
            }
        } catch (Exception ignored) {
            // 无法获取MAC地址，使用随机数
        }
        SecureRandom random = new SecureRandom();
        return random.nextLong() & 0xFFFFFFFFFFFFL; // 保留48位
    }

    // 生成版本1的UUID
    public static synchronized UUID generate() {
        long timestamp = (System.currentTimeMillis() * 10000) + START_EPOCH + (System.nanoTime() % 10000 / 10);

        // 处理时钟回拨或同一时间戳
        if (timestamp <= lastTimestamp.get()) {
            clockSequence.incrementAndGet();
        } else {
            lastTimestamp.set(timestamp);
        }

        // 构造UUID的各个部分
        long timeLow = timestamp & 0xFFFFFFFFL;
        long timeMid = (timestamp >> 32) & 0xFFFFL;
        long timeHiAndVersion = (timestamp >> 48) & 0x0FFFL;
        timeHiAndVersion |= (1L << 12); // 设置版本号为1

        long msb = (timeLow << 32) | (timeMid << 16) | timeHiAndVersion;
        long lsb = (clockSequence.get() & 0x3FFFL) << 48; // 时钟序列（14位）
        lsb |= nodeIdentifier; // 节点ID（48位）
        lsb |= 0x8000000000000000L; // 设置变体位为标准（10xxxxxx）

        return new UUID(msb, lsb);
    }
}
